home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / libtiff / tools / tiffdither.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  8.4 KB  |  314 lines

  1. /* $Header: /usr/people/sam/tiff/tools/RCS/tiffdither.c,v 1.26 1996/01/10 19:35:37 sam Rel $ */
  2.  
  3. /*
  4.  * Copyright (c) 1988-1996 Sam Leffler
  5.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "tiffio.h"
  32.  
  33. #define    streq(a,b)    (strcmp(a,b) == 0)
  34. #define    strneq(a,b,n)    (strncmp(a,b,n) == 0)
  35.  
  36. #define    CopyField(tag, v) \
  37.     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
  38.  
  39. uint32    imagewidth;
  40. uint32    imagelength;
  41. int    threshold = 128;
  42.  
  43. static    void usage(void);
  44.  
  45. /* 
  46.  * Floyd-Steinberg error propragation with threshold.
  47.  * This code is stolen from tiffmedian.
  48.  */
  49. static void
  50. fsdither(TIFF* in, TIFF* out)
  51. {
  52.     unsigned char *outline, *inputline, *inptr;
  53.     short *thisline, *nextline, *tmpptr;
  54.     register unsigned char    *outptr;
  55.     register short *thisptr, *nextptr;
  56.     register uint32 i, j;
  57.     uint32 imax, jmax;
  58.     int lastline, lastpixel;
  59.     int bit;
  60.     tsize_t outlinesize;
  61.  
  62.     imax = imagelength - 1;
  63.     jmax = imagewidth - 1;
  64.     inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
  65.     thisline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
  66.     nextline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
  67.     outlinesize = TIFFScanlineSize(out);
  68.     outline = (unsigned char *) _TIFFmalloc(outlinesize);
  69.  
  70.     /*
  71.      * Get first line
  72.      */
  73.     if (TIFFReadScanline(in, inputline, 0, 0) <= 0)
  74.         return;
  75.     inptr = inputline;
  76.     nextptr = nextline;
  77.     for (j = 0; j < imagewidth; ++j)
  78.         *nextptr++ = *inptr++;
  79.     for (i = 1; i < imagelength; ++i) {
  80.         tmpptr = thisline;
  81.         thisline = nextline;
  82.         nextline = tmpptr;
  83.         lastline = (i == imax);
  84.         if (TIFFReadScanline(in, inputline, i, 0) <= 0)
  85.             break;
  86.         inptr = inputline;
  87.         nextptr = nextline;
  88.         for (j = 0; j < imagewidth; ++j)
  89.             *nextptr++ = *inptr++;
  90.         thisptr = thisline;
  91.         nextptr = nextline;
  92.         _TIFFmemset(outptr = outline, 0, outlinesize);
  93.         bit = 0x80;
  94.         for (j = 0; j < imagewidth; ++j) {
  95.             register int v;
  96.  
  97.             lastpixel = (j == jmax);
  98.             v = *thisptr++;
  99.             if (v < 0)
  100.                 v = 0;
  101.             else if (v > 255)
  102.                 v = 255;
  103.             if (v > threshold) {
  104.                 *outptr |= bit;
  105.                 v -= 255;
  106.             }
  107.             bit >>= 1;
  108.             if (bit == 0) {
  109.                 outptr++;
  110.                 bit = 0x80;
  111.             }
  112.             if (!lastpixel)
  113.                 thisptr[0] += v * 7 / 16;
  114.             if (!lastline) {
  115.                 if (j != 0)
  116.                     nextptr[-1] += v * 3 / 16;
  117.                 *nextptr++ += v * 5 / 16;
  118.                 if (!lastpixel)
  119.                     nextptr[0] += v / 16;
  120.             }
  121.         }
  122.         if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
  123.             break;
  124.     }
  125.     _TIFFfree(inputline);
  126.     _TIFFfree(thisline);
  127.     _TIFFfree(nextline);
  128.     _TIFFfree(outline);
  129. }
  130.  
  131. static    uint16 compression = COMPRESSION_LZW;
  132. static    uint16 predictor = 0;
  133. static    uint32 group3options = 0;
  134.  
  135. static void
  136. processG3Options(char* cp)
  137. {
  138.     if (cp = strchr(cp, ':')) {
  139.         do {
  140.             cp++;
  141.             if (strneq(cp, "1d", 2))
  142.                 group3options &= ~GROUP3OPT_2DENCODING;
  143.             else if (strneq(cp, "2d", 2))
  144.                 group3options |= GROUP3OPT_2DENCODING;
  145.             else if (strneq(cp, "fill", 4))
  146.                 group3options |= GROUP3OPT_FILLBITS;
  147.             else
  148.                 usage();
  149.         } while (cp = strchr(cp, ':'));
  150.     }
  151. }
  152.  
  153. static int
  154. processCompressOptions(char* opt)
  155. {
  156.     if (streq(opt, "none"))
  157.         compression = COMPRESSION_NONE;
  158.     else if (streq(opt, "packbits"))
  159.         compression = COMPRESSION_PACKBITS;
  160.     else if (strneq(opt, "g3", 2)) {
  161.         processG3Options(opt);
  162.         compression = COMPRESSION_CCITTFAX3;
  163.     } else if (streq(opt, "g4"))
  164.         compression = COMPRESSION_CCITTFAX4;
  165.     else if (strneq(opt, "lzw", 3)) {
  166.         char* cp = strchr(opt, ':');
  167.         if (cp)
  168.             predictor = atoi(cp+1);
  169.         compression = COMPRESSION_LZW;
  170.     } else if (strneq(opt, "zip", 3)) {
  171.         char* cp = strchr(opt, ':');
  172.         if (cp)
  173.             predictor = atoi(cp+1);
  174.         compression = COMPRESSION_DEFLATE;
  175.     } else
  176.         return (0);
  177.     return (1);
  178. }
  179.  
  180. int
  181. main(int argc, char* argv[])
  182. {
  183.     TIFF *in, *out;
  184.     uint16 samplesperpixel, bitspersample = 1, shortv;
  185.     float floatv;
  186.     char thing[1024];
  187.     uint32 rowsperstrip = (uint32) -1;
  188.     int onestrip = 0;
  189.     uint16 fillorder = 0;
  190.     int c;
  191.     extern int optind;
  192.     extern char *optarg;
  193.  
  194.     while ((c = getopt(argc, argv, "c:f:r:t:")) != -1)
  195.         switch (c) {
  196.         case 'c':        /* compression scheme */
  197.             if (!processCompressOptions(optarg))
  198.                 usage();
  199.             break;
  200.         case 'f':        /* fill order */
  201.             if (streq(optarg, "lsb2msb"))
  202.                 fillorder = FILLORDER_LSB2MSB;
  203.             else if (streq(optarg, "msb2lsb"))
  204.                 fillorder = FILLORDER_MSB2LSB;
  205.             else
  206.                 usage();
  207.             break;
  208.         case 'r':        /* rows/strip */
  209.             rowsperstrip = atoi(optarg);
  210.             onestrip = 0;
  211.             break;
  212.         case 't':
  213.             threshold = atoi(optarg);
  214.             if (threshold < 0)
  215.                 threshold = 0;
  216.             else if (threshold > 255)
  217.                 threshold = 255;
  218.             break;
  219.         case '?':
  220.             usage();
  221.             /*NOTREACHED*/
  222.         }
  223.     if (argc - optind < 2)
  224.         usage();
  225.     in = TIFFOpen(argv[optind], "r");
  226.     if (in == NULL)
  227.         return (-1);
  228.     TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  229.     if (samplesperpixel != 1) {
  230.         fprintf(stderr, "%s: Not a b&w image.\n", argv[0]);
  231.         return (-1);
  232.     }
  233.     TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  234.     if (bitspersample != 8) {
  235.         fprintf(stderr,
  236.             " %s: Sorry, only handle 8-bit samples.\n", argv[0]);
  237.         return (-1);
  238.     }
  239.     out = TIFFOpen(argv[optind+1], "w");
  240.     if (out == NULL)
  241.         return (-1);
  242.     CopyField(TIFFTAG_IMAGEWIDTH, imagewidth);
  243.     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
  244.     TIFFSetField(out, TIFFTAG_IMAGELENGTH, imagelength-1);
  245.     TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
  246.     TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
  247.     TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  248.     TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
  249.     TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
  250.     TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
  251.     sprintf(thing, "Dithered B&W version of %s", argv[optind]);
  252.     TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing);
  253.     CopyField(TIFFTAG_ORIENTATION, shortv);
  254.     CopyField(TIFFTAG_XRESOLUTION, floatv);
  255.     CopyField(TIFFTAG_YRESOLUTION, floatv);
  256.     CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
  257.     if (onestrip)
  258.         rowsperstrip = imagelength-1;
  259.     else
  260.         rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
  261.     TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
  262.     switch (compression) {
  263.     case COMPRESSION_CCITTFAX3:
  264.         TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, group3options);
  265.         break;
  266.     case COMPRESSION_LZW:
  267.     case COMPRESSION_DEFLATE:
  268.         if (predictor)
  269.             TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
  270.         break;
  271.     }
  272.     fsdither(in, out);
  273.     TIFFClose(in);
  274.     TIFFClose(out);
  275.     return (0);
  276. }
  277.  
  278. char* stuff[] = {
  279. "usage: tiffdither [options] input.tif output.tif",
  280. "where options are:",
  281. " -r #        make each strip have no more than # rows",
  282. " -f lsb2msb    force lsb-to-msb FillOrder for output",
  283. " -f msb2lsb    force msb-to-lsb FillOrder for output",
  284. " -c lzw[:opts]    compress output with Lempel-Ziv & Welch encoding",
  285. " -c zip[:opts]    compress output with deflate encoding",
  286. " -c packbits    compress output with packbits encoding",
  287. " -c g3[:opts]    compress output with CCITT Group 3 encoding",
  288. " -c g4        compress output with CCITT Group 4 encoding",
  289. " -c none    use no compression algorithm on output",
  290. "",
  291. "Group 3 options:",
  292. " 1d        use default CCITT Group 3 1D-encoding",
  293. " 2d        use optional CCITT Group 3 2D-encoding",
  294. " fill        byte-align EOL codes",
  295. "For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
  296. "",
  297. "LZW and deflate options:",
  298. " #        set predictor value",
  299. "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
  300. NULL
  301. };
  302.  
  303. static void
  304. usage(void)
  305. {
  306.     char buf[BUFSIZ];
  307.     int i;
  308.  
  309.     setbuf(stderr, buf);
  310.     for (i = 0; stuff[i] != NULL; i++)
  311.         fprintf(stderr, "%s\n", stuff[i]);
  312.     exit(-1);
  313. }
  314.